package rolesystem.agentlogic.managers;

import java.util.ArrayList;
import java.awt.*;

import javax.swing.*;

import rolesystem.agentlogic.GUI.EnvVisualizer;
import rolesystem.agentlogic.GUI.GuiControls;
import rolesystem.agentlogic.GUI.StatePanel;
import rolesystem.agentlogic.utilityclasses.AgentMap;
import rolesystem.agentlogic.utilityclasses.PositionSq;
import rolesystem.agentlogic.utilityclasses.SearchResult;
import rolesystem.agentlogic.utilityclasses.Square;
import rolesystem.jade.agents.carry.carrier.CarrierSL;

public class EnvironmentManager 
{
	/**
	 * X Size of the environment.
	 */
	static public final int ENV_MAX_X = 30;
	
	/**
	 * Y Size of the environment.
	 */
	static public final int ENV_MAX_Y = 30;
	
	static public int FOOD_NUMBER = 15;
	
	static public int FOOD_NUMBER_WEIGHT_2 = 1;
	
	static public int OBSTACLES_NUMBER = 15;
	
	/**
	 * The environment, a matrix of Square.
	 */
	private static ArrayList<Square>[][] env = new ArrayList[ENV_MAX_X][ENV_MAX_Y];
	
	public static EnvVisualizer canvas;
	public static GuiControls envControls;
	public static StatePanel stateVisualization;
	
	private static JFrame frame;

	
	static	
	{
		// Initialize the Square(s)
		reset();
		 
		// Initialize the Visualization
		initVisualization();
		 
		DataOutputManager.printString("## Environment Initialized ##"); 
	}
	
	public static void initVisualization()
	{
		frame = new JFrame();
	    frame.setSize(1000, 800);
	    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		 
		canvas = new EnvVisualizer(20,ENV_MAX_X,ENV_MAX_Y);
		canvas.setSize(600, 600);
		canvas.setLocation(0, 0);
		 
		envControls = new GuiControls();
		envControls.setSize(1000, 200);
		envControls.setLocation(0, 600);
		
		stateVisualization= new StatePanel();		
		stateVisualization.setSize(400, 600);
		stateVisualization.setLocation(600, 0);
		 
		EnvVisualizer.updateObj(env);
		 
		frame.setLayout(null);
		 
	    frame.getContentPane().add(canvas);
	    frame.getContentPane().add(envControls);
	    frame.getContentPane().add(stateVisualization);
	    frame.setVisible(true);
		  
	}
	
	public synchronized static void resetText()
	{
		stateVisualization.reset(); // Problema: interferisce con visualizzazione
	}
	
	
  public static void reset()
	{
	  	// Initialize the Square(s)
	  	for(int i=0;i< ENV_MAX_X; i++)
	  	{
	  		for(int j=0;j< ENV_MAX_Y; j++)
	  		{
	  			env[i][j]=new ArrayList<Square>();
	  			env[i][j].add(new Square());
	  		}    
	  	}  
			
	  	int rand_x=0;
	 	int rand_y=0;
			
	 	// Create obstacles
		for(int i=0;i< OBSTACLES_NUMBER; i++)
		{
			rand_x =(int) (Math.random() * (ENV_MAX_X-1));
			rand_y= (int) (Math.random() * (ENV_MAX_Y-1));
			
			if(env[rand_x][rand_y].get(0).getBlocked()==false)
				env[rand_x][rand_y].get(0).setBlocked(true);
			else
				i--;
		} 
				
		// Create the Objects (non null weights)
		for(int i=0;i< FOOD_NUMBER; i++)
	    {
			rand_x =(int) (Math.random() * (ENV_MAX_X-1));
			rand_y= (int) (Math.random() * (ENV_MAX_Y-1));
				 
			if(env[rand_x][rand_y].get(0).getBlocked()==false && env[rand_x][rand_y].get(0).getWeight()==0)
				env[rand_x][rand_y].get(0).setWeight(1);
			else
				i--;
			 	 
		} 
		
		// Create the Objects (weight=2)
		for(int i=0;i< FOOD_NUMBER_WEIGHT_2; i++)
		{
			rand_x =(int) (Math.random() * (ENV_MAX_X-1));
			rand_y= (int) (Math.random() * (ENV_MAX_Y-1));
						 
			if(env[rand_x][rand_y].get(0).getBlocked()==false && env[rand_x][rand_y].get(0).getWeight()==0)
				env[rand_x][rand_y].get(0).setWeight(2);
			else
				i--;		 	 
		} 
	}
  
  public static ArrayList<SearchResult> reqSearch(int x, int y, int range)
	{
	  ArrayList<SearchResult> search_result= new ArrayList<SearchResult>();
	  
	  PositionSq min= new PositionSq(x-range,y-range);
	  PositionSq max= new PositionSq(x+range,y+range);
	  
	  min.checkAndCorrectBounds();
	  max.checkAndCorrectBounds();
	  
	  for(int i=min.pos_x;i<= max.pos_x; i++)
	  {
		 for(int j=min.pos_y;j<= max.pos_y; j++)
		 {
		   if(env[i][j].get(0).getWeight()!=0 && (env[i][j].get(0).getReserved()==false || CarrierSL.contactType==3))
		   {   
			   search_result.add(new SearchResult(i,j,env[i][j].get(0).getWeight()));
			   System.out.println("Search - Match Found - x:" + i + " y:"+ j + " Peso:"+ env[i][j].get(0).getWeight()); 
		   }
		 }    
	  }
	  
	  return search_result;
	}
  
  
  
  public static Square pickObject(PositionSq object_position)
	{	  
	  if(object_position.checkBounds())
		return null;
	  
	  Square pickedObject=env[object_position.pos_x][object_position.pos_y].get(0);
	  
	  if(pickedObject.getWeight()==0)
		  return null;
	  
	  
	  Square emptyObject=env[object_position.pos_x][object_position.pos_y].get(0);
	  emptyObject.setWeight(0);
	  emptyObject.setReserved(false);
	  env[object_position.pos_x][object_position.pos_y].set(0,emptyObject);
	  
	  updateVisualization();

	  return pickedObject;
	}
  
  public static boolean getObjectExist(PositionSq position)
	{
	  if(env[position.pos_x][position.pos_y].get(0).getWeight()==0)
		  return false;
	  else
		  return true;
	}
  
  public static boolean getObstacle(int x,int y)
	{
	  return env[x][y].get(0).getBlocked();  
	}
  
  public static boolean getObstacle(PositionSq position)
	{
	  return env[position.pos_x][position.pos_y].get(0).getBlocked();  
	}
  
  public static boolean getReserved(PositionSq position)
	{
	  return env[position.pos_x][position.pos_y].get(0).getReserved();  
	}
  
  public static boolean getReservedAndSetIfFalse(PositionSq position)
	{
	  return env[position.pos_x][position.pos_y].get(0).getReservedAndSetIfFalse();  
	}
  
  public static void setReserved(PositionSq position, boolean reserved)
	{
	   env[position.pos_x][position.pos_y].get(0).setReserved(reserved);  
	}
  
  public static PositionSq getAlternativeRoute(int position_x,int position_y,int dir_x,int dir_y)
	{
	  ArrayList<PositionSq> possible_route= new ArrayList<PositionSq>();
	  ArrayList<Integer> distanceFromTarget= new ArrayList<Integer>();
	  
	  // Check for possible position choices
	  for(int i=-1;i<=1;i++)
	  {
		  for(int j=-1;j<=1;j++)
		  {
			  if(i==0 && j==0)
				  continue;
			  
			  PositionSq candidate_pos=new PositionSq(position_x+i, position_y+j);
			  if(candidate_pos.checkBounds())
				  continue;
			  
			  if(candidate_pos.pos_x==(position_x+dir_x) && candidate_pos.pos_y==(position_y+dir_y))
				  continue;
			  
			  if(env[candidate_pos.pos_x][candidate_pos.pos_y].get(0).getBlocked()==false)
			  {  
				  possible_route.add(candidate_pos); 
				  distanceFromTarget.add(new Integer(Math.abs(dir_x-i) + Math.abs(dir_y-j) )); 
			  }
		  }  
	  }  
	  
	  // Calculate minimum distance from the "perfect" but blocked route
	  int min_dist=100;
	  ArrayList<Integer> indexArray= new ArrayList<Integer>();
	  
	  for(int i=0;i<possible_route.size();i++)
	  {
		  if(Math.abs(distanceFromTarget.get(i).intValue())<min_dist)
		  {  
			indexArray.clear();
			indexArray.add(new Integer(i));
			min_dist=Math.abs(distanceFromTarget.get(i).intValue());
		  }
		  if(Math.abs(distanceFromTarget.get(i).intValue())==min_dist)
		  {  
			indexArray.add(new Integer(i));  
			min_dist=Math.abs(distanceFromTarget.get(i).intValue());
		  }
	  }
	  
	  int index=(int)(Math.random()* (indexArray.size()-1)); 
	  
	  return possible_route.get(indexArray.get(index).intValue()); 
	}
  
  public static void updateAgentPosition(AgentMap updatedAgent)
	{
	  EnvVisualizer.updateAgent(updatedAgent);
	}
  
  public static void stopSignal()
	{
	  envControls.startStopButtonClicked();
	}
  
  public static void updateVisualization()
	{
	  Graphics g = canvas.getGraphics();
	  canvas.update(g);
	}
  
}

